/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 */
import fs from 'fs';
import path from 'path';
import process from 'process';

import { coreParameter } from '../../base/internal/data/global-core-parameters.js';
import { HvigorConfig } from '../../base/util/hvigor-config-reader.js';
import { HvigorCliOptions } from '../../base/util/options/hvigor-cli-options.js';
import { DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME, DOT, PROPERTIES } from '../const/const.js';
import { HVIGOR_PROJECT_WRAPPER_HOME, HVIGOR_USER_HOME } from '../const/path-const.js';
import { parseJsonFile } from './parse-json/parse-json-util.js';

export class HvigorConfigLoader {
  private readonly hvigorConfig: HvigorConfig | undefined;
  private readonly configPropertyMap: Map<string, unknown>;
  private static instance: HvigorConfigLoader | undefined;
  private static config: Record<string, string> | undefined = undefined;
  /**
   * 初始化读取两个配置文件 userhome下的和项目目录下的
   *
   */
  constructor() {
    this.configPropertyMap = new Map<string, unknown>();
    const hvigorConfigPath = path.resolve(HVIGOR_PROJECT_WRAPPER_HOME, DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME);
    if (!fs.existsSync(hvigorConfigPath)) {
      return;
    }
    const projectJson5Obj = parseJsonFile(hvigorConfigPath);
    const globalConfigFile = path.resolve(HVIGOR_USER_HOME, DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME);
    let userHomeJson5Obj;
    if (fs.existsSync(globalConfigFile)) {
      userHomeJson5Obj = parseJsonFile(globalConfigFile);

      // 工程目录下优先，相同名字后面覆盖前面
      projectJson5Obj.properties = { ...userHomeJson5Obj.properties, ...projectJson5Obj.properties };
    }
    this.hvigorConfig = projectJson5Obj; // 100个例子 改了properties 也只改其中一个
  }

  public static init(cliOpts?: HvigorCliOptions) {
    if (cliOpts === undefined) {
      process.env.config = undefined;
      return;
    }

    const configs = HvigorConfigLoader.getConfigs(); // 读取命令行的参数
    let cliConfigs: Record<string, string> = {};

    // 读取cliOpts.config的参数
    cliOpts.config?.forEach((cliConfig) => {
      const config = cliConfig.split('=');
      if (config.length === 2) {
        cliConfigs[config[0]] = config[config.length - 1];
        this.initCommandLineProperties(config[0], config[config.length - 1]);
      }
    });

    // 读取cliOpts.prop的参数
    if (Array.isArray(cliOpts.prop)) {
      cliOpts.prop?.forEach((cliConfig) => {
        const config = cliConfig.split('=');
        if (config.length === 2) {
          cliConfigs[config[0]] = config[config.length - 1];
          this.initCommandLineProperties(config[0], config[config.length - 1]);
        }
      });
    }

    cliConfigs = { ...configs, ...cliConfigs };
    process.env.config = JSON.stringify(cliConfigs); // 放入环境变量中，不然子进程读取不到
  }

  private static initCommandLineProperties(configKey: string, configValue: string): void {
    if (!configKey.startsWith(`${PROPERTIES + DOT}`)) {
      // properties.
      return;
    }
    const key = configKey.substring(`${PROPERTIES + DOT}`.length);
    coreParameter.properties[key] = this.convertToParamValue(configValue);
  }

  private static convertToParamValue(value: string) {
    let temp: number | boolean | string = Number(value);
    if (
      value.length <= 16 && // 避免科学计数法精度丢失，超过16位不转为number
      !isNaN(temp)
    ) {
      return temp;
    }

    temp = value === 'true' ? true : value === 'false' ? false : temp;

    if (typeof temp === 'boolean') {
      return temp;
    }
    return value.trim();
  }

  public getHvigorConfig(): HvigorConfig | undefined {
    return this.hvigorConfig;
  }

  /**
   * 获取properties中的某个配置，会优先尝试读取命令行中是否存在这个数据，然后是工程下hvigor-config.jons5中
   * 最后是userHome下的hvigor-config.json5
   *
   * @param key 配置名
   * @return 读取到的值
   */
  public getPropertiesConfigValue<T>(key: string): T | undefined {
    if(this.configPropertyMap.has(key)) {
      return this.configPropertyMap.get(key) as T;
    }
    // 从命令行中读取
    const propertiesConfig = HvigorConfigLoader.getConfigs()['properties.'.concat(key)];

    // 先从环境变量中读取，如果环境变量中没有则尝试在命令行中读取
    const configsValue = process.env.config !== undefined ? JSON.parse(process.env.config)['properties.'.concat(key)] ?? propertiesConfig : propertiesConfig;

    if (configsValue !== undefined) {
      const parsedConfigValue =  this.parseConfigValue<T>(configsValue);
      this.configPropertyMap.set(key,parsedConfigValue);
      return parsedConfigValue;
    }
    if (this.hvigorConfig === undefined) {
      this.configPropertyMap.set(key, undefined);
      return undefined;
    }
    const hvigorConfigPropertyValue = this.hvigorConfig.properties ? this.hvigorConfig.properties[key] : undefined;
    this.configPropertyMap.set(key, hvigorConfigPropertyValue);
    return hvigorConfigPropertyValue;
  }

  /**
   *  daemon模式下，常驻线程会保存上一次的静态变量 instance, 如果两次构建中间 hvigor-config.json被修改 instance就需要被更新
   */
  public static clean() {
    if (HvigorConfigLoader.instance) {
      HvigorConfigLoader.instance = undefined;
    }
    if (HvigorConfigLoader.config) {
      HvigorConfigLoader.config = undefined;
    }
  }

  /**
   * 获取线程级存储的config loader单例
   */
  public static getInstance(): HvigorConfigLoader {
    if (!HvigorConfigLoader.instance) {
      HvigorConfigLoader.instance = new HvigorConfigLoader();
    } // 当前worker没有实例 启动
    // 如果有实例 是否已经检查过变动
    return HvigorConfigLoader.instance;
  }

  /**
   * 尝试在启动的命令行(process.argv)中找到所有的config，不能使用命令行工具commands解析，会和工程中其他的内容冲突
   *
   * @return 所有的config组成的数组
   */
  private static getConfigs() {
    if (this.config) {
      return this.config;
    }
    const args = process.argv.slice(2); // 去掉前两个元素（node 路径 和 文件路径）
    const argPrefix = /^(--config|-c).*/;
    const argPrefixSpace = /^(--config|-c)$/;
    const values: Record<string, string> = {};

    for (const [index, arg] of args.entries()) {
      if (argPrefixSpace.test(arg)) {
        const config = args[index + 1].split('=');
        if (config.length === 2) {
          values[config[0]] = config[config.length - 1];
        }
      } else if (argPrefix.test(arg)) {
        const match = arg.match(argPrefix);
        if (match && match[0].length < arg.length) {
          const config = arg.substring(match[0].length).split('=');
          if (config.length === 2) {
            values[config[0]] = config[config.length - 1];
          }
        }
      }
    }
    this.config = values;
    return values;
  }

  /**
   * 解析
   * @param value
   * @private
   */
  private parseConfigValue<T>(value: string): T {
    // 尝试将字符串转换为布尔值
    if (value.toLowerCase() === 'true') {
      return true as unknown as T;
    } else if (value.toLowerCase() === 'false') {
      return false as unknown as T;
    }

    // 尝试将字符串转换为数字
    const numValue = Number(value);
    if (!isNaN(numValue)) {
      return numValue as unknown as T;
    }

    // 如果没有其他匹配，则返回原始字符串
    return value as unknown as T;
  }
}
